#include<iostream>
#include<string>
#include<pthread.h>
#include<unistd.h>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cassert>


using namespace std;

void* start_routine(void* args)
{
    string name = static_cast<const char*>(args);//安全的进行强制类型转化
    while(true)
    {
        printf("new thread create success, name: %s\n",name.c_str());
        sleep(1);
        //一个线程如果出现了异常, 会影响其他线程, (健壮性/鲁棒性较差)
        //进程信号, 信号是整体发给进程的, 因为线程这里出现了异常, OS就识别到了,
        //是哪个进程出现的问题,在这里所有线程的进程pid都是相等的所以OS会给每个线程的PCB都写入信号
        // int* p = nullptr;
        // *p = 0;
    }
}
void test()
{
    pthread_t id;
    pthread_create(&id,nullptr,start_routine,(void*)"thread one");
    while(true)
    {
        printf("new thread create success, name: main thread\n");
        sleep(1);
    }
}

void test1()
{
    vector<pthread_t> tids;
#define NUM 10
    for(int i = 0;i < NUM;i++)
    {
        pthread_t tid;
        char namebuffer[64];
        snprintf(namebuffer,sizeof(namebuffer),"%s : %d","thread",i);
        //namebuffer是缓冲区的起始地址, 创建的新线程谁先运行不确定, 所以缓冲区有可能被覆盖, 所以会出现序号紊乱的问题
        pthread_create(&tid,nullptr,start_routine,namebuffer);
        //pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
        //sleep(1);
    }
    while(true)
    {
        printf("new thread create success, name: main thread\n");
        sleep(1);
    }
}

class ThreadData
{
public:
    int number;
    pthread_t tid;
    char namebuffer[64];
};
//start_routine1这个函数现在是被10个线程执行  这个函数现在是重入状态
//该函数是可重入函数
//在函数内定义的变量, 都叫做局部变量, 具有临时性, 在多线程情况下, 也适用, 也没有问题, 其实每一个线程都有自己独立的栈结构
void* start_routine1(void* args)
{
    sleep(1);
    ThreadData* td = static_cast<ThreadData*>(args);
    int cnt = 10;
    while(cnt)
    {
        printf("cnt : %d  &cnt : 0x%x\n",cnt,&cnt);
        cnt--;
        //printf("new thread create success, name: %s cnt : %d\n",td->namebuffer,cnt--);
        sleep(1);
        // exit(0);//不能用来终止线程, 因为exit是用来终止进程的, 任何一个执行流调用exit都会让整个进程退出
        // pthread_exit(nullptr);
        //return nullptr;
    }
    //delete td;
    //return nullptr;//线程函数结束, return的时候, 线程就算终止了
    //pthread_exit(nullptr);
    //return (void*)td->number;//void* ret = (void*)td->number其实就是把这4个字节的内容写到了这8个字节的空间里
    pthread_exit((void*)td->number);
}
void test2()
{
    vector<ThreadData*> threads;
#define NUM 10
    for(int i = 0;i < NUM;i++)
    {
        ThreadData* td = new ThreadData();
        td->number = i + 1;
        snprintf(td->namebuffer,sizeof(td->namebuffer),"%s : %d","thread",i);
        pthread_create(&td->tid,nullptr,start_routine1,td);//td是拷贝了一份给的线程因为接收的时候是void* args所以这份数据就属于线程私有的了
        threads.push_back(td);
    }
    for(auto& iter : threads)
    {
        printf("create thread: %s : %d : success\n",iter->namebuffer,iter->tid);
    }
    for(auto& iter : threads)
    {
        void* ret = nullptr;//注意: 这里是void*
        int n = pthread_join(iter->tid,&ret);//内部会做void** retp     *retp = return (void*)td->number
        assert(n == 0);
        printf("join : %s success , number : %lld\n",iter->namebuffer,(long long)ret);
        delete iter;
    }
    printf("main thread quit\n");
    // while(true)
    // {
    //     printf("new thread create success, name: main thread\n");
    //     sleep(1);
    // }
}

void* start_routine2(void* args)
{
    sleep(1);
    ThreadData* td = static_cast<ThreadData*>(args);
    int cnt = 10;
    while(cnt)
    {
        printf("cnt : %d  &cnt : 0x%x\n",cnt,&cnt);
        cnt--;
        sleep(1);
    }
    return (void*)100;
}
void test3()
{
    vector<ThreadData*> threads;
#define NUM 10
    for(int i = 0;i < NUM;i++)
    {
        ThreadData* td = new ThreadData();
        td->number = i + 1;
        snprintf(td->namebuffer,sizeof(td->namebuffer),"%s : %d","thread",i);
        pthread_create(&td->tid,nullptr,start_routine2,td);
        threads.push_back(td);
    }
    for(auto& iter : threads)
    {
        printf("create thread: %s : %d : success\n",iter->namebuffer,iter->tid);
    }
    sleep(5);
    for(int i = 0;i < threads.size() / 2;i++)
    {
        pthread_cancel(threads[i]->tid);
        printf("pthread_cancel: %s : %d : success\n",threads[i]->namebuffer,threads[i]->tid);
    }
    for(auto& iter : threads)
    {
        void* ret = nullptr;
        int n = pthread_join(iter->tid,&ret);
        assert(n == 0);
        printf("join : %s success , exit_code : %lld\n",iter->namebuffer,(long long)ret);
        delete iter;
    }
    printf("main thread quit\n");
}
int main()
{
    //test();
    //创建一批线程
    //test1();
    //正确的创建一批线程
    //test2();
    test3();
    return 0;
}